#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include "lecture_dossier.h"
#include <errno.h>
#include "generation_cle.h"
#include "md5.h"

#define LONG_MAX 10000000

struct file *liste_fichier(char *dossier_donnees, int taille_piece){

  struct file *liste =creer_file();
  DIR *resultat = NULL;
  struct dirent* fichier = NULL;
  unsigned long taille;
  FILE * in;
  char *tampon;
  md5_byte_t digest[16];
  char cle[16*2 + 1];
  int nb_pieces;
  int nb_octets;
  unsigned char *buffermap;
  unsigned char buffermap_byte;
  struct stat fichier_stat;   

  //A modifier dans le fichier de config
  char *chemin_donnees = malloc(sizeof(char)*(strlen(dossier_donnees)+2));
  strcpy(chemin_donnees, "./");
  strcat(chemin_donnees, dossier_donnees);
  resultat = opendir(chemin_donnees);
  if(resultat == NULL){
    perror("Impossible d'ouvrir le dossier");
    exit(1);
  }
  char *chemin_donnees_bis = malloc(sizeof(char)*(strlen(dossier_donnees)+1));
  strcpy(chemin_donnees_bis, dossier_donnees);
  strcat(chemin_donnees_bis, "/");
  while((fichier = readdir(resultat)) != NULL){
    if (fichier->d_name[0]!='.'&&fichier->d_name[strlen(fichier->d_name)-1]!='~')
      {
	tampon=malloc(sizeof(fichier->d_name)+sizeof(chemin_donnees_bis));
	tampon=strcpy(tampon,chemin_donnees_bis);
	tampon=strcat(tampon,fichier->d_name);
	// calcul taille
	in = fopen(tampon,"r");
	if(stat(tampon,&fichier_stat) != 0)
	  {
	    perror("ERROR stat");
	    return NULL; 
	  }
	taille = fichier_stat.st_size;
	free(tampon);
	// calcul nb pieces
	nb_pieces = taille/taille_piece;
	if (taille%taille_piece != 0)
	  nb_pieces++;
	// generation cle
	generate_key(in, taille, nb_pieces, taille_piece, digest);
	int di;
	for (di = 0; di < 16; ++di)
	  snprintf(cle + di * 2, sizeof(cle)+di*2-1, "%02x", digest[di]);
	// calcul buffermap et nb octets du buffermap
	nb_octets = nb_pieces/8;
	if (nb_pieces%8 != 0)
	  nb_octets++;
	buffermap = malloc(sizeof(char)*nb_octets);   
	char tmp;
	int tmp2 = nb_pieces;
	for (int k = 0; k < nb_octets; k++)
	  {
	    buffermap_byte = 0;
	    tmp = 1;
	    for (int i = 0; i < 8; i++)
	      {
		if (tmp2 > 0)
		  {
		    buffermap_byte += tmp;
		    tmp *= 2;
		    tmp2--;
		  }
	      }
	    buffermap[k] = buffermap_byte;
	  }
	enfiler(fichier->d_name,taille,taille_piece, cle, buffermap, nb_octets, liste);
	fclose(in);
      }
  }
  if(closedir(resultat) == -1){
    perror("Impossible de fermer le dossier");
    exit(-1);
  }
  return liste;
}

int creer_file_dl(struct fichier_partage *fichier, char *dossier_config){
  FILE * out;
  char*tampon=malloc(sizeof(fichier->nom_fichier)+sizeof(dossier_config+4/*"config/.dl"*/));
  tampon=strcpy(tampon, dossier_config/*"config/"*/);
  tampon=strcat(tampon, "/");
  tampon=strcat(tampon,fichier->nom_fichier);
  tampon=strcat(tampon,".dl");
  out=fopen(tampon,"r+");
  if(out!=NULL){
    fclose(out);
    return EXIT_FAILURE;//le fichier existe déjà
  }
  out=fopen(tampon,"a");
  free(tampon);
  fprintf(out,"nom=%s\n",fichier->nom_fichier);
  fprintf(out,"cle=%s\n",fichier->cle_fichier);
  fprintf(out,"taille=%li\n",fichier->taille_fichier);
  fprintf(out,"piece=%li\n",fichier->taille_piece);
  fprintf(out,"taillebuffermap=%i\n",fichier->taille_buffermap);
  fprintf(out,"buffermap=");
  fwrite(fichier->buffermap,sizeof(char),fichier->taille_buffermap,out);
  fclose(out);
  return EXIT_SUCCESS;
}

struct file* lire_file_dl(char *dossier_config){
 struct file *liste =creer_file();
 char nom[255];
 unsigned long taille;
 unsigned long piece;
 char cle[33];
 unsigned char * buffermap;
 int taille_buffermap;
 DIR *resultat = NULL;
 struct dirent* fichier = NULL;
 FILE* in;
 char *chemin_dl = malloc(sizeof(char)*(strlen(dossier_config)+2));
 strcpy(chemin_dl, "./");
 strcat(chemin_dl, dossier_config);
 resultat = opendir(chemin_dl/*"./config"*/);
  if(resultat == NULL){
    perror("Impossible d'ouvrir le dossier");
    return NULL;
  }
  char *chemin_dl_bis = malloc(sizeof(char)*(strlen(dossier_config)+1));
  strcpy(chemin_dl_bis, dossier_config);
  strcat(chemin_dl_bis, "/");
  while((fichier = readdir(resultat)) != NULL){
    if (fichier->d_name[0]!='.'&&fichier->d_name[strlen(fichier->d_name)-1]!='~'){
      char *tampon=malloc(sizeof(fichier->d_name)+sizeof(chemin_dl_bis/*"config/"*/));
      tampon=strcpy(tampon, chemin_dl_bis/*"config/"*/);
	tampon=strcat(tampon,fichier->d_name);
	in = fopen(tampon,"r");
	free(tampon);
	char tempc[20];
	fread(tempc,sizeof(char),4,in);
	tempc[4]='\0';
	if(strcmp(tempc,"nom=")!=0){
	  perror("Fichier .dl corrompu ou invalide");
	  exit(-1);
	}
	fgets(nom,254,in);
	nom[strlen(nom)-1]='\0';
	fread(tempc,sizeof(char),4,in);
	tempc[4]='\0';
	if(strcmp(tempc,"cle=")!=0){
	  perror("Fichier .dl corrompu ou invalide");
	  exit(-1);
	}
	fgets(cle,33,in);
	fread(tempc,sizeof(char),1,in);
	fread(tempc,sizeof(char),7,in);
	tempc[7]='\0';
	if(strcmp(tempc,"taille=")!=0){
	  perror("Fichier .dl corrompu ou invalide");
	  exit(-1);
	}
	fgets(tempc,255,in);
	taille=atol(tempc);
	fread(tempc,sizeof(char),6,in);
	tempc[6]='\0';
	if(strcmp(tempc,"piece=")!=0){
	  perror("Fichier .dl corrompu ou invalide");
	  exit(-1);
	}
	fgets(tempc,255,in);
	piece=atol(tempc);
	fread(tempc,sizeof(char),16,in);
	tempc[16]='\0';
	if(strcmp(tempc,"taillebuffermap=")!=0){
	  perror("Fichier .dl corrompu ou invalide");
	  exit(-1);
	}
	fgets(tempc,255,in);
	taille_buffermap=atoi(tempc);
	fread(tempc,sizeof(char),10,in);
	tempc[10]='\0';
	if(strcmp(tempc,"buffermap=")!=0){
	  perror("Fichier .dl corrompu ou invalide");
	  exit(-1);
	}
	buffermap=malloc(sizeof(char)*taille_buffermap);
	fread(buffermap,sizeof(char),taille_buffermap,in);
	enfiler(nom,taille,piece,cle,buffermap,taille_buffermap,liste);
	free(buffermap);
	fclose(in);
    }
  }
  if(closedir(resultat) == -1){
    perror("Impossible de fermer le dossier");
    exit(-1);
  }
  return liste;
}
 

int modifie_buffermap(struct fichier_partage*fichier, char *dossier_config,int mode){//1 pour ecrire 2 pour lire
  FILE * out;
  struct stat fichier_stat;    
  char*tampon=malloc(sizeof(char)*(strlen(fichier->nom_fichier)+strlen(dossier_config)+4));
  tampon=strcpy(tampon,dossier_config);
  tampon=strcat(tampon, "/");
  tampon=strcat(tampon,fichier->nom_fichier);
  tampon=strcat(tampon,".dl");
  out=fopen(tampon,"r+");
  if(out==NULL){
    return EXIT_FAILURE;//le fichier n'existe pas
  }
  if(stat(tampon,&fichier_stat) != 0)
    {
      perror("ERROR stat");
      return EXIT_FAILURE;
    }
  int maxsize = fichier_stat.st_size;
  free(tampon);
  char *tempc=malloc(sizeof(char)*maxsize);
  fgets(tempc,maxsize,out);
  fgets(tempc,maxsize,out);
  fgets(tempc,maxsize,out);
  fgets(tempc,maxsize,out);
  fgets(tempc,maxsize,out);
  fread(tempc,sizeof(char),10,out);
  tempc[10]='\0';
  if(strcmp(tempc,"buffermap=")!=0){
    perror("Fichier .dl corrompu ou invalide");
    return EXIT_FAILURE;
  }
  if(mode == WRITE)
    {
      fwrite(fichier->buffermap,sizeof(char),fichier->taille_buffermap,out);
    }
 if(mode == READ)
    {
      fread(fichier->buffermap,sizeof(char),fichier->taille_buffermap,out);
    }
  free(tempc);
  fclose(out);
 if(mode != READ && mode != WRITE)
   {
     return EXIT_FAILURE;
   }
  return EXIT_SUCCESS;
}

int supprime_file_dl(struct fichier_partage * fichier, char *dossier_config){
  char*tampon=malloc(sizeof(fichier->nom_fichier)+sizeof(dossier_config)+4/*"config/.dl"*/);
  int result;
  tampon=strcpy(tampon,dossier_config/*"config/"*/);
  tampon=strcat(tampon, "/");
  tampon=strcat(tampon,fichier->nom_fichier);
  tampon=strcat(tampon,".dl");
  result = remove(tampon);
  free(tampon);
  return result;
}
